package com.its.common.net.client.impl;

import cn.hutool.core.lang.Assert;
import com.its.common.net.client.BaseClient;
import com.its.common.net.client.config.ClientParams;
import com.its.common.net.client.handler.GenericHeartbeatDetector;
import com.its.common.net.client.handler.IdleStateChecker;
import com.its.common.net.core.handler.TailHandler;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * @Author xiaxp
 * @Date 9/13/22 14:02
 * @Description
 */
@Slf4j
public class TcpClient extends BaseClient<ByteBuf> {

    public TcpClient(ClientParams clientParams) {
        super(clientParams);
        Assert.notNull(serverAttr, "连接的服务器地址不能为空.");
        Assert.notNull(decoderBuildParams, "客户端解码器不能为空.");
        Assert.notNull(handlers, "客户端处理器不能为空.");
        Assert.isFalse(handlers.isEmpty(), "客户端处理器不能为空.");
    }

    /**
     * 连接执行的操作
     */
    @Override
    protected ChannelFuture doStart(int port) {
        this.bootstrap.group(this.group)
            .channel(NioSocketChannel.class)
            .option(ChannelOption.TCP_NODELAY, true)
            .option(ChannelOption.SO_KEEPALIVE, false)
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
            .option(ChannelOption.SO_SNDBUF, READ_WRITE_BUF_CAP)
            .option(ChannelOption.SO_RCVBUF, READ_WRITE_BUF_CAP)
            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
            .handler(new LoggingHandler(LogLevel.INFO))
            .handler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    ByteToMessageDecoder decoder = decoderBuildParams.buildDecoderInstance();
                    pipeline.addLast(defaultEventExecutorGroup, new IdleStateChecker(readerIdleTime));
                    pipeline.addLast(defaultEventExecutorGroup, decoder);
                    if (null != heartbeatDefine && heartbeatDefine.active()
                        && heartbeatDefine.heartbeatInterval() > 0) {
                        pipeline.addLast(defaultEventExecutorGroup,
                            new GenericHeartbeatDetector(TcpClient.this, heartbeatDefine));
                    }
                    List<SimpleChannelInboundHandler> handlerList = TcpClient.this.getHandlers();
                    handlerList.forEach((handler) -> pipeline.addLast(defaultEventExecutorGroup, handler));

                    pipeline.addLast(defaultEventExecutorGroup, new TailHandler());
                }
            });
        ChannelFuture future = this.bootstrap.localAddress(this.localPort)
            .connect(serverAttr.getAddress(), serverAttr.getPort());
        return future;
    }

    /**
     * 连接成功后立刻执行的操作
     *
     * @param channel channel
     */
    @Override
    protected void doAfterConnected(Channel channel) {
        log.debug("TcpClient doAfterConnected... ok... ... ...");
    }
}
